home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Developer / Marlais 0.3.1 / gc4.1-mac / src / test.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-26  |  20.0 KB  |  815 lines  |  [TEXT/R*ch]

  1. /* 
  2.  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3.  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  4.  *
  5.  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  6.  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  7.  *
  8.  * Permission is hereby granted to copy this garbage collector for any purpose,
  9.  * provided the above notices are retained on all copies.
  10.  */
  11. /* Boehm, May 6, 1994 3:32 pm PDT */
  12. /* An incomplete test for the garbage collector.          */
  13. /* Some more obscure entry points are not tested at all.    */
  14.  
  15. # include <stdlib.h>
  16. # include <stdio.h>
  17. # include "gc.h"
  18. # include "gc_typed.h"
  19. # include "gc_priv.h"    /* For output and some statistics    */
  20. # include "config.h"
  21.  
  22. // #define GC_DEBUG
  23.  
  24. # ifdef MSWIN32
  25. #   include <windows.h>
  26. # endif
  27.  
  28. # ifdef PCR
  29. #   include "th/PCR_ThCrSec.h"
  30. #   include "th/PCR_Th.h"
  31. # endif
  32.  
  33. # ifdef SOLARIS_THREADS
  34. #   include <thread.h>
  35. #   include <synch.h>
  36. # endif
  37.  
  38. # if defined(PCR) || defined(SOLARIS_THREADS)
  39. #   define THREADS
  40. # endif
  41.  
  42. # ifdef AMIGA
  43.    long __stack = 200000;
  44. # endif
  45.  
  46. # define FAIL (void)abort()
  47.  
  48. /* AT_END may be defined to excercise the interior pointer test    */
  49. /* if the collector is configured with ALL_INTERIOR_POINTERS.   */
  50. /* As it stands, this test should succeed with either        */
  51. /* configuration.  In the FIND_LEAK configuration, it should    */
  52. /* find lots of leaks, since we free almost nothing.        */
  53.  
  54. struct SEXPR {
  55.     struct SEXPR * sexpr_car;
  56.     struct SEXPR * sexpr_cdr;
  57. };
  58.  
  59. # ifdef __STDC__
  60.     typedef void * void_star;
  61. # else
  62.     typedef char * void_star;
  63. # endif
  64.  
  65. typedef struct SEXPR * sexpr;
  66.  
  67. extern sexpr cons();
  68.  
  69. # undef nil
  70. # define nil ((sexpr) 0)
  71. # define car(x) ((x) -> sexpr_car)
  72. # define cdr(x) ((x) -> sexpr_cdr)
  73. # define is_nil(x) ((x) == nil)
  74.  
  75.  
  76. int extra_count = 0;        /* Amount of space wasted in cons node */
  77.  
  78. /* Silly implementation of Lisp cons. Intentionally wastes lots of space */
  79. /* to test collector.                                                    */
  80. sexpr cons (x, y)
  81. sexpr x;
  82. sexpr y;
  83. {
  84.     register sexpr r;
  85.     register int *p;
  86.     register my_extra = extra_count;
  87.     
  88.     r = (sexpr) GC_MALLOC_STUBBORN(sizeof(struct SEXPR) + my_extra);
  89.     if (r == 0) {
  90.         (void)GC_printf0("Out of memory\n");
  91.         exit(1);
  92.     }
  93.     for (p = (int *)r;
  94.          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
  95.     if (*p) {
  96.         (void)GC_printf1("Found nonzero at 0x%lx - allocator is broken\n",
  97.                      (unsigned long)p);
  98.         FAIL;
  99.         }
  100.         *p = 13;
  101.     }
  102. #   ifdef AT_END
  103.     r = (sexpr)((char *)r + (my_extra & ~7));
  104. #   endif
  105.     r -> sexpr_car = x;
  106.     r -> sexpr_cdr = y;
  107.     my_extra++;
  108.     if ( my_extra >= 5000 ) {
  109.         extra_count = 0;
  110.     } else {
  111.         extra_count = my_extra;
  112.     }
  113.     GC_END_STUBBORN_CHANGE((char *)r);
  114.     return(r);
  115. }
  116.  
  117. sexpr small_cons (x, y)
  118. sexpr x;
  119. sexpr y;
  120. {
  121.     register sexpr r;
  122.     
  123.     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
  124.     if (r == 0) {
  125.         (void)GC_printf0("Out of memory\n");
  126.         exit(1);
  127.     }
  128.     r -> sexpr_car = x;
  129.     r -> sexpr_cdr = y;
  130.     return(r);
  131. }
  132.  
  133. sexpr small_cons_uncollectable (x, y)
  134. sexpr x;
  135. sexpr y;
  136. {
  137.     register sexpr r;
  138.     
  139.     r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
  140.     if (r == 0) {
  141.         (void)GC_printf0("Out of memory\n");
  142.         exit(1);
  143.     }
  144.     r -> sexpr_car = x;
  145.     r -> sexpr_cdr = (sexpr) (~(unsigned long)y);
  146.     return(r);
  147. }
  148.  
  149. /* Return reverse(x) concatenated with y */
  150. sexpr reverse1(x, y)
  151. sexpr x, y;
  152. {
  153.     if (is_nil(x)) {
  154.         return(y);
  155.     } else {
  156.         return( reverse1(cdr(x), cons(car(x), y)) );
  157.     }
  158. }
  159.  
  160. sexpr reverse(x)
  161. sexpr x;
  162. {
  163.     return( reverse1(x, nil) );
  164. }
  165.  
  166. sexpr ints(low, up)
  167. int low, up;
  168. {
  169.     if (low > up) {
  170.     return(nil);
  171.     } else {
  172.         return(small_cons(small_cons((sexpr)low, (sexpr)0), ints(low+1, up)));
  173.     }
  174. }
  175.  
  176. /* Too check uncollectable allocation we build lists with disguised cdr    */
  177. /* pointers, and make sure they don't go away.                */
  178. sexpr uncollectable_ints(low, up)
  179. int low, up;
  180. {
  181.     if (low > up) {
  182.     return(nil);
  183.     } else {
  184.         return(small_cons_uncollectable(small_cons((sexpr)low, (sexpr)0),
  185.                uncollectable_ints(low+1, up)));
  186.     }
  187. }
  188.  
  189. void check_ints(list, low, up)
  190. sexpr list;
  191. int low, up;
  192. {
  193.     if ((int)(car(car(list))) != low) {
  194.         (void)GC_printf0(
  195.            "List reversal produced incorrect list - collector is broken\n");
  196.         exit(1);
  197.     }
  198.     if (low == up) {
  199.         if (cdr(list) != nil) {
  200.            (void)GC_printf0("List too long - collector is broken\n");
  201.            exit(1);
  202.         }
  203.     } else {
  204.         check_ints(cdr(list), low+1, up);
  205.     }
  206. }
  207.  
  208. # define UNCOLLECTABLE_CDR(x) (sexpr)(~(unsigned long)(cdr(x)))
  209.  
  210. void check_uncollectable_ints(list, low, up)
  211. sexpr list;
  212. int low, up;
  213. {
  214.     if ((int)(car(car(list))) != low) {
  215.         (void)GC_printf0(
  216.            "Uncollectable list corrupted - collector is broken\n");
  217.         exit(1);
  218.     }
  219.     if (low == up) {
  220.         if (UNCOLLECTABLE_CDR(list) != nil) {
  221.            (void)GC_printf0("Uncollectable ist too long - collector is broken\n");
  222.            exit(1);
  223.         }
  224.     } else {
  225.         check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up);
  226.     }
  227. }
  228.  
  229. /* Not used, but useful for debugging: */
  230. void print_int_list(x)
  231. sexpr x;
  232. {
  233.     if (is_nil(x)) {
  234.         (void)GC_printf0("NIL\n");
  235.     } else {
  236.         (void)GC_printf1("(%ld)", (long)(car(car(x))));
  237.         if (!is_nil(cdr(x))) {
  238.             (void)GC_printf0(", ");
  239.             (void)print_int_list(cdr(x));
  240.         } else {
  241.             (void)GC_printf0("\n");
  242.         }
  243.     }
  244. }
  245.  
  246. /* Try to force a to be strangely aligned */
  247. struct {
  248.   char dummy;
  249.   sexpr aa;
  250. } A;
  251. #define a A.aa
  252.  
  253. /*
  254.  * Repeatedly reverse lists built out of very different sized cons cells.
  255.  * Check that we didn't lose anything.
  256.  */
  257. void reverse_test()
  258. {
  259.     int i;
  260.     sexpr b;
  261.     sexpr c;
  262.     sexpr d;
  263.     sexpr e;
  264. #   if defined(MSWIN32) || defined(MACINTOSH)
  265.       /* Win32S only allows 128K stacks */
  266. #     define BIG 1000
  267. #   else
  268. #     define BIG 4500
  269. #   endif
  270.  
  271.     a = ints(1, 49);
  272.     b = ints(1, 50);
  273.     c = ints(1, BIG);
  274.     d = uncollectable_ints(1, 100);
  275.     e = uncollectable_ints(1, 1);
  276.     /* Superficially test interior pointer recognition on stack */
  277.     c = (sexpr)((char *)c + sizeof(char *));
  278.     d = (sexpr)((char *)d + sizeof(char *));
  279. #   ifdef __STDC__
  280.         GC_FREE((void *)e);
  281. #   else
  282.         GC_FREE((char *)e);
  283. #   endif
  284.     for (i = 0; i < 50; i++) {
  285.         b = reverse(reverse(b));
  286.     }
  287.     check_ints(b,1,50);
  288.     for (i = 0; i < 60; i++) {
  289.         /* This maintains the invariant that a always points to a list of */
  290.         /* 49 integers.  Thus this is thread safe without locks.      */
  291.         a = reverse(reverse(a));
  292.         check_ints(a,1,49);
  293. #    if !defined(AT_END) && !defined(THREADS)
  294.       /* This is not thread safe, since realloc explicitly deallocates */
  295.           if (i & 1) {
  296.             a = (sexpr)GC_REALLOC((void_star)a, 500);
  297.           } else {
  298.             a = (sexpr)GC_REALLOC((void_star)a, 8200);
  299.           }
  300. #    endif
  301.     }
  302.     check_ints(a,1,49);
  303.     check_ints(b,1,50);
  304.     c = (sexpr)((char *)c - sizeof(char *));
  305.     d = (sexpr)((char *)d - sizeof(char *));
  306.     check_ints(c,1,BIG);
  307.     check_uncollectable_ints(d, 1, 100);
  308.     a = b = c = 0;
  309. }
  310.  
  311. /*
  312.  * The rest of this builds balanced binary trees, checks that they don't
  313.  * disappear, and tests finalization.
  314.  */
  315. typedef struct treenode {
  316.     int level;
  317.     struct treenode * lchild;
  318.     struct treenode * rchild;
  319. } tn;
  320.  
  321. int finalizable_count = 0;
  322. int finalized_count = 0;
  323. int dropped_something = 0;
  324.  
  325. # ifdef __STDC__
  326.   void finalizer(void * obj, void * client_data)
  327. # else
  328.   void finalizer(obj, client_data)
  329.   char * obj;
  330.   char * client_data;
  331. # endif
  332. {
  333.   tn * t = (tn *)obj;
  334.  
  335. # ifdef PCR
  336.      PCR_ThCrSec_EnterSys();
  337. # endif
  338. # ifdef SOLARIS_THREADS
  339.     static mutex_t incr_lock;
  340.     mutex_lock(&incr_lock);
  341. # endif
  342.   if ((int)client_data != t -> level) {
  343.      (void)GC_printf0("Wrong finalization data - collector is broken\n");
  344.      FAIL;
  345.   }
  346.   finalized_count++;
  347. # ifdef PCR
  348.     PCR_ThCrSec_ExitSys();
  349. # endif
  350. # ifdef SOLARIS_THREADS
  351.     mutex_unlock(&incr_lock);
  352. # endif
  353. }
  354.  
  355. size_t counter = 0;
  356.  
  357. # define MAX_FINALIZED 8000
  358.  
  359. # if !defined(MACINTOSH)
  360. GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0};
  361. #else
  362. // too big for THINK_C. have to allocate it dynamically.
  363. GC_word *live_indicators = 0;
  364. #endif
  365.  
  366. int live_indicators_count = 0;
  367.  
  368. tn * mktree(n)
  369. int n;
  370. {
  371.     tn * result = (tn *)GC_MALLOC(sizeof(tn));
  372.  
  373. #if defined(MACINTOSH)
  374.     /* get around static data limitations. */
  375.     if (!live_indicators)
  376.         live_indicators = (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
  377.     if (!live_indicators) {
  378.         (void)GC_printf0("Out of memory\n");
  379.         exit(1);
  380.     }
  381. #endif
  382.  
  383.     if (n == 0) return(0);
  384.     if (result == 0) {
  385.         (void)GC_printf0("Out of memory\n");
  386.         exit(1);
  387.     }
  388.     result -> level = n;
  389.     result -> lchild = mktree(n-1);
  390.     result -> rchild = mktree(n-1);
  391.     if (counter++ % 17 == 0 && n >= 2) {
  392.         tn * tmp = result -> lchild -> rchild;
  393.         
  394.         result -> lchild -> rchild = result -> rchild -> lchild;
  395.         result -> rchild -> lchild = tmp;
  396.     }
  397.     if (counter++ % 119 == 0) {
  398.         int my_index;
  399.         
  400.         {
  401. #      ifdef PCR
  402.          PCR_ThCrSec_EnterSys();
  403. #      endif
  404. #      ifdef SOLARIS_THREADS
  405.         static mutex_t incr_lock;
  406.         mutex_lock(&incr_lock);
  407. #      endif
  408.         /* Losing a count here causes erroneous report of failure. */
  409.           finalizable_count++;
  410.           my_index = live_indicators_count++;
  411. #      ifdef PCR
  412.          PCR_ThCrSec_ExitSys();
  413. #      endif
  414. #      ifdef SOLARIS_THREADS
  415.         mutex_unlock(&incr_lock);
  416. #      endif
  417.     }
  418.  
  419.         GC_REGISTER_FINALIZER((void_star)result, finalizer, (void_star)n,
  420.                       (GC_finalization_proc *)0, (void_star *)0);
  421.         live_indicators[my_index] = 13;
  422.         if (GC_general_register_disappearing_link(
  423.              (void_star *)(&(live_indicators[my_index])),
  424.              (void_star)result) != 0) {
  425.              GC_printf0("GC_general_register_disappearing_link failed\n");
  426.              FAIL;
  427.         }
  428.         if (GC_unregister_disappearing_link(
  429.              (void_star *)
  430.                 (&(live_indicators[my_index]))) == 0) {
  431.              GC_printf0("GC_unregister_disappearing_link failed\n");
  432.              FAIL;
  433.         }
  434.         if (GC_general_register_disappearing_link(
  435.              (void_star *)(&(live_indicators[my_index])),
  436.              (void_star)result) != 0) {
  437.              GC_printf0("GC_general_register_disappearing_link failed 2\n");
  438.              FAIL;
  439.         }
  440.     }
  441.     return(result);
  442. }
  443.  
  444. void chktree(t,n)
  445. tn *t;
  446. int n;
  447. {
  448.     if (n == 0 && t != 0) {
  449.         (void)GC_printf0("Clobbered a leaf - collector is broken\n");
  450.         FAIL;
  451.     }
  452.     if (n == 0) return;
  453.     if (t -> level != n) {
  454.         (void)GC_printf1("Lost a node at level %lu - collector is broken\n",
  455.                  (unsigned long)n);
  456.         FAIL;
  457.     }
  458.     if (counter++ % 373 == 0) (void) GC_MALLOC(counter%5001);
  459.     chktree(t -> lchild, n-1);
  460.     if (counter++ % 73 == 0) (void) GC_MALLOC(counter%373);
  461.     chktree(t -> rchild, n-1);
  462. }
  463.  
  464. # ifdef SOLARIS_THREADS
  465. thread_key_t fl_key;
  466.  
  467. void * alloc8bytes()
  468. {
  469.     void ** my_free_list_ptr;
  470.     void * my_free_list;
  471.     
  472.     if (thr_getspecific(fl_key, (void **)(&my_free_list_ptr)) != 0) {
  473.         (void)GC_printf0("thr_getspecific failed\n");
  474.         FAIL;
  475.     }
  476.     if (my_free_list_ptr == 0) {
  477.         my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
  478.         if (thr_setspecific(fl_key, my_free_list_ptr) != 0) {
  479.             (void)GC_printf0("thr_setspecific failed\n");
  480.             FAIL;
  481.         }
  482.     }
  483.     my_free_list = *my_free_list_ptr;
  484.     if (my_free_list == 0) {
  485.         my_free_list = GC_malloc_many(8);
  486.         if (my_free_list == 0) {
  487.             (void)GC_printf0("alloc8bytes out of memory\n");
  488.             FAIL;
  489.         }
  490.     }
  491.     *my_free_list_ptr = GC_NEXT(my_free_list);
  492.     GC_NEXT(my_free_list) = 0;
  493.     return(my_free_list);
  494. }
  495.  
  496. #else
  497. # define alloc8bytes() GC_MALLOC_ATOMIC(8)
  498. #endif
  499.  
  500. void alloc_small(n)
  501. int n;
  502. {
  503.     register int i;
  504.     
  505.     for (i = 0; i < n; i += 8) {
  506.         if (alloc8bytes() == 0) {
  507.             (void)GC_printf0("Out of memory\n");
  508.             FAIL;
  509.         }
  510.     }
  511. }
  512.  
  513. void tree_test()
  514. {
  515.     tn * root;
  516.     register int i;
  517.     
  518.     root = mktree(16);
  519.     alloc_small(5000000);
  520.     chktree(root, 16);
  521.     if (finalized_count && ! dropped_something) {
  522.         (void)GC_printf0("Premature finalization - collector is broken\n");
  523.         FAIL;
  524.     }
  525.     dropped_something = 1;
  526.     root = mktree(16);
  527.     chktree(root, 16);
  528.     for (i = 16; i >= 0; i--) {
  529.         root = mktree(i);
  530.         chktree(root, i);
  531.     }
  532.     alloc_small(5000000);
  533. }
  534.  
  535. unsigned n_tests = 0;
  536.  
  537. /* A very simple test of explicitly typed allocation    */
  538. void typed_test()
  539. {
  540.     GC_word * old, * new;
  541.     GC_word bm3 = 0x3;
  542.     GC_word bm2 = 0x2;
  543.     GC_word bm_large = 0xf7ff7fff;
  544.     GC_descr d1 = GC_make_descriptor(&bm3, 2);
  545.     GC_descr d2 = GC_make_descriptor(&bm2, 2);
  546. #   ifndef LINT
  547.       GC_descr dummy = GC_make_descriptor(&bm_large, 32);
  548. #   endif
  549.     GC_descr d3 = GC_make_descriptor(&bm_large, 32);
  550.     register int i;
  551.     
  552.     old = 0;
  553.     for (i = 0; i < 4000; i++) {
  554.         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1);
  555.         new[0] = 17;
  556.         new[1] = (GC_word)old;
  557.         old = new;
  558.         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d2);
  559.         new[0] = 17;
  560.         new[1] = (GC_word)old;
  561.         old = new;
  562.         new = (GC_word *) GC_malloc_explicitly_typed(33 * sizeof(GC_word), d3);
  563.         new[0] = 17;
  564.         new[1] = (GC_word)old;
  565.         old = new;
  566.         new = (GC_word *) GC_calloc_explicitly_typed(4, 2 * sizeof(GC_word),
  567.                                  d1);
  568.         new[0] = 17;
  569.         new[1] = (GC_word)old;
  570.         old = new;
  571.         if (i & 0xff) {
  572.           new = (GC_word *) GC_calloc_explicitly_typed(7, 3 * sizeof(GC_word),
  573.                                  d2);
  574.         } else {
  575.           new = (GC_word *) GC_calloc_explicitly_typed(1001,
  576.                                      3 * sizeof(GC_word),
  577.                                    d2);
  578.         }
  579.         new[0] = 17;
  580.         new[1] = (GC_word)old;
  581.         old = new;
  582.     }
  583.     for (i = 0; i < 20000; i++) {
  584.         if (new[0] != 17) {
  585.             (void)GC_printf1("typed alloc failed at %lu\n",
  586.                          (unsigned long)i);
  587.             FAIL;
  588.         }
  589.         new[0] = 0;
  590.         old = new;
  591.         new = (GC_word *)(old[1]);
  592.     }
  593. }
  594.  
  595. void run_one_test()
  596. {
  597.     DCL_LOCK_STATE;
  598.     
  599. #   ifndef GC_DEBUG
  600.     if (GC_size(GC_MALLOC(7)) != 8
  601.         || GC_size(GC_MALLOC(15)) != 16) {
  602.         (void)GC_printf0("GC_size produced unexpected results\n");
  603.         FAIL;
  604.     }
  605. #   endif
  606.     reverse_test();
  607. #   ifdef PRINTSTATS
  608.     GC_printf0("-------------Finished reverse_test\n");
  609. #   endif
  610.     typed_test();
  611. #   ifdef PRINTSTATS
  612.     GC_printf0("-------------Finished typed_test\n");
  613. #   endif
  614.     tree_test();
  615.     LOCK();
  616.     n_tests++;
  617.     UNLOCK();
  618.     
  619. }
  620.  
  621. void check_heap_stats()
  622. {
  623.     unsigned long max_heap_sz;
  624.     register int i;
  625.     int still_live;
  626.     
  627.     if (sizeof(char *) > 4) {
  628.         max_heap_sz = 13000000;
  629.     } else {
  630.         max_heap_sz = 10000000;
  631.     }
  632. #   ifdef GC_DEBUG
  633.     max_heap_sz *= 2;
  634. #       ifdef SPARC
  635.         max_heap_sz *= 2;
  636. #       endif
  637. #   endif
  638.     /* Garbage collect repeatedly so that all inaccessible objects    */
  639.     /* can be finalized.                        */
  640.       for (i = 0; i < 16; i++) {
  641.         GC_gcollect();
  642.       }
  643.     (void)GC_printf1("Completed %lu tests\n", (unsigned long)n_tests);
  644.     (void)GC_printf2("Finalized %lu/%lu objects - ",
  645.                  (unsigned long)finalized_count,
  646.                  (unsigned long)finalizable_count);
  647.     if (finalized_count > finalizable_count
  648.         || finalized_count < finalizable_count/2) {
  649.         (void)GC_printf0("finalization is probably broken\n");
  650.         FAIL;
  651.     } else {
  652.         (void)GC_printf0("finalization is probably ok\n");
  653.     }
  654.     still_live = 0;
  655.     for (i = 0; i < MAX_FINALIZED; i++) {
  656.         if (live_indicators[i] != 0) {
  657.             still_live++;
  658.         }
  659.     }
  660.     if (still_live != finalizable_count - finalized_count) {
  661.         (void)GC_printf1
  662.             ("%lu disappearing links remain - disappearing links are broken\n",
  663.              (unsigned long) still_live);
  664.         FAIL;
  665.     }
  666.     (void)GC_printf1("Total number of bytes allocated is %lu\n",
  667.             (unsigned long)
  668.                    WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc));
  669.     (void)GC_printf1("Final heap size is %lu bytes\n",
  670.                  (unsigned long)GC_get_heap_size());
  671.     if (WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc)
  672.         < 33500000*n_tests) {
  673.         (void)GC_printf0("Incorrect execution - missed some allocations\n");
  674.         FAIL;
  675.     }
  676.     if (GC_get_heap_size() > max_heap_sz*n_tests) {
  677.         (void)GC_printf0("Unexpected heap growth - collector may be broken\n");
  678.         FAIL;
  679.     }
  680.     (void)GC_printf0("Collector appears to work\n");
  681. }
  682.  
  683. #if defined(MACINTOSH)
  684. void SetMinimumStack(long minSize)
  685. {
  686.     long newApplLimit;
  687.  
  688.     if (minSize > LMGetDefltStack())
  689.     {
  690.         newApplLimit = (long) GetApplLimit() - (minSize - LMGetDefltStack());
  691. //        newApplLimit = (long) GetApplLimit() - minSize;
  692.         SetApplLimit((Ptr) newApplLimit);
  693.         MaxApplZone();
  694.     }
  695. }
  696.  
  697. #define cMinStackSpace (256L * 1024L)
  698.  
  699. #endif
  700.  
  701. #if !defined(PCR) && !defined(SOLARIS_THREADS) || defined(LINT)
  702. #ifdef MSWIN32
  703.   int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
  704. #else
  705.   int main()
  706. #endif
  707. {
  708.     n_tests = 0;
  709.     
  710. #if defined(MACINTOSH)
  711.     // make sure we have lots and lots of stack space.
  712.     SetMinimumStack(cMinStackSpace);
  713.     // cheat and let stdio initialize toolbox for us.
  714.     printf("testing GC Macintosh port.\n");
  715.     GC_init();                // or MERGE_SIZES won't work?
  716. //    GC_clear_roots();        // don't try to find things in global space.
  717. #endif
  718.  
  719. #   if defined(MPROTECT_VDB) || defined(PROC_VDB)
  720.       GC_enable_incremental();
  721.       (void) GC_printf0("Switched to incremental mode\n");
  722. #     if defined(MPROTECT_VDB)
  723.     (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
  724. #     else
  725.     (void)GC_printf0("Reading dirty bits from /proc\n");
  726. #      endif
  727. #   endif
  728.  
  729.     run_one_test();
  730.     check_heap_stats();
  731.     (void)fflush(stdout);
  732. #   ifdef LINT
  733.     /* Entry points we should be testing, but aren't.           */
  734.     /* Some can be tested by defining GC_DEBUG at the top of this file */
  735.     /* This is a bit SunOS4 specific.                   */            
  736.     GC_noop(GC_expand_hp, GC_add_roots, GC_clear_roots,
  737.             GC_register_disappearing_link,
  738.             GC_print_obj, GC_debug_change_stubborn,
  739.             GC_debug_end_stubborn_change, GC_debug_malloc_uncollectable,
  740.             GC_debug_free, GC_debug_realloc, GC_generic_malloc_words_small,
  741.             GC_init, GC_make_closure, GC_debug_invoke_finalizer,
  742.             GC_page_was_ever_dirty, GC_is_fresh,
  743.         GC_malloc_ignore_off_page);
  744. #   endif
  745.     return(0);
  746. }
  747. # endif
  748.  
  749. #ifdef PCR
  750. test()
  751. {
  752.     PCR_Th_T * th1;
  753.     PCR_Th_T * th2;
  754.     int code;
  755.  
  756.     n_tests = 0;
  757.     GC_enable_incremental();
  758.     th1 = PCR_Th_Fork(run_one_test, 0);
  759.     th2 = PCR_Th_Fork(run_one_test, 0);
  760.     run_one_test();
  761.     if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
  762.         != PCR_ERes_okay || code != 0) {
  763.         (void)GC_printf0("Thread 1 failed\n");
  764.     }
  765.     if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
  766.         != PCR_ERes_okay || code != 0) {
  767.         (void)GC_printf0("Thread 2 failed\n");
  768.     }
  769.     check_heap_stats();
  770.     (void)fflush(stdout);
  771.     return(0);
  772. }
  773. #endif
  774.  
  775. #ifdef SOLARIS_THREADS
  776. void * thr_run_one_test(void * arg)
  777. {
  778.     run_one_test();
  779.     return(0);
  780. }
  781. main()
  782. {
  783.     thread_t th1;
  784.     thread_t th2;
  785.     int code;
  786.  
  787.     n_tests = 0;
  788.     GC_enable_incremental();
  789.     if (thr_keycreate(&fl_key, GC_free) != 0) {
  790.         (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
  791.         FAIL;
  792.     }
  793.     if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, 0, &th1)) != 0) {
  794.         (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
  795.         FAIL;
  796.     }
  797.     if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, THR_NEW_LWP, &th2)) != 0) {
  798.         (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
  799.         FAIL;
  800.     }
  801.     run_one_test();
  802.     if ((code = thr_join(th1, 0, 0)) != 0) {
  803.         (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
  804.         FAIL;
  805.     }
  806.     if (thr_join(th2, 0, 0) != 0) {
  807.         (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
  808.         FAIL;
  809.     }
  810.     check_heap_stats();
  811.     (void)fflush(stdout);
  812.     return(0);
  813. }
  814. #endif
  815.